package com.happyhome.controller;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.imageio.ImageIO;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.imgscalr.Scalr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

import com.happyhome.constants.AppConstant;
import com.happyhome.datamodel.House;
import com.happyhome.datamodel.Image;
import com.happyhome.datamodel.Parameter;
import com.happyhome.datamodel.Room;
import com.happyhome.datamodel.RoomUtility;
import com.happyhome.datamodel.Utility;
import com.happyhome.services.HouseService;
import com.happyhome.services.ImageService;
import com.happyhome.services.ParameterService;
import com.happyhome.services.RoomService;
import com.happyhome.services.RoomUtilityService;
import com.happyhome.services.UtilityService;

@Controller
@RequestMapping("/admin/rooms")
public class RoomController {
	
	private static final Logger log = LoggerFactory.getLogger(RoomController.class);
	
	@Autowired
	private UtilityService utilityService;
	
	@Autowired
	private HouseService houseSerive;
	
	@Autowired
	private RoomService roomService;
	
	@Autowired
	private RoomUtilityService roomUtilityService;
	
	@Autowired
	private ImageService imageService;
	
	@Autowired
	private ServletContext context;
	
	@Autowired
	private ParameterService parameterService;
	
	@RequestMapping(value = "/list", method = RequestMethod.GET)
	public ModelAndView login() {
		return new ModelAndView("/admin/rooms/list");
	}
	
	@RequestMapping(value = "/rental", method = RequestMethod.GET)
	public ModelAndView rental() {
		return new ModelAndView("/admin/rooms/rentalRoom");
	}
	
	@RequestMapping(value = "/new", method = RequestMethod.GET)
	public ModelAndView newRoom(@RequestParam(value = "error", required = false) String error,
			@RequestParam(value = "logout", required = false) String logout) {
		ModelAndView model = new ModelAndView("/admin/rooms/new");
		List<Utility> utilities = utilityService.getAllUtilities();
		List<House> houses = houseSerive.getAll();
		
		model.addObject("utilities", utilities);
		model.addObject("houses", houses);
		return model;
	}
	
	/* form new House submit form */
	@RequestMapping(value = "/newRoomSubmit", method = RequestMethod.POST)
	public @ResponseBody String newRoomSubmit(HttpServletRequest request){
		Map<String, String[]> multiParameters = request.getParameterMap();
		Room room = setValueForRoom(null, multiParameters);
		List<Utility> utilities = setUtilities(multiParameters);
		if(room != null){ // input invalid in setValueForHouse
			room = roomService.merge(room);
			if(room != null){
				for(Utility utility :utilities){
					RoomUtility roomUtility = new RoomUtility();
					roomUtility.setRoom(room);
					roomUtility.setUtility(utility);
					roomUtility.setStatus(Boolean.valueOf("true"));
					roomUtilityService.merge(roomUtility);
				}
			}
			return room.getIdRoom() + ";" + room.getNameRoom();
		}
		return "fail";
	}
	
	private Room setValueForRoom(Room room, Map<String, String[]> multiParameters){
		if(room == null){
			room = new Room();
		}
		
		String[] codeRoom = multiParameters.get(AppConstant.CODE_ROOM);
		if(codeRoom != null ){
			room.setCodeRoom(codeRoom[0]);
			multiParameters.remove(AppConstant.CODE_ROOM);
		}
		
		String[] deposit = multiParameters.get(AppConstant.DEPOSIT_ROOM);
		if(deposit != null ){
			try {
				String depositCost = deposit[0].replace(",", "");
				room.setDepositRoom(Long.parseLong(depositCost));
				multiParameters.remove(AppConstant.DEPOSIT_ROOM);
			} catch (NumberFormatException e) {
				e.printStackTrace();
				return null;
			}
		}
		
		String[] description = multiParameters.get(AppConstant.DESCRIPTION);
		if(description != null){
			room.setDescription(description[0]);
			multiParameters.remove(AppConstant.DESCRIPTION);
		}
		
		String[] floor = multiParameters.get(AppConstant.FLOOR);
		if(floor != null ){
			try {
				room.setFloor(Integer.parseInt(floor[0]));
				multiParameters.remove(AppConstant.FLOOR);
			} catch (NumberFormatException e) {
				e.printStackTrace();
				return null;
			}
		}
		
		String[] nameRoom = multiParameters.get(AppConstant.NAME_ROOM);
		if(nameRoom != null ){
			room.setNameRoom(nameRoom[0]);
			multiParameters.remove(AppConstant.NAMEHOUSE);
		}
		String[] maxPerson = multiParameters.get(AppConstant.NUMBER_MAX_PERSON);
		if(maxPerson != null ){
			try{
				room.setNumberMaxPerson(Integer.parseInt(maxPerson[0]));
				multiParameters.remove(AppConstant.NUMBER_MAX_PERSON);
			}catch(NumberFormatException ex){
				return null;
			}
		}
		String[] priceRoom = multiParameters.get(AppConstant.PRICE_ROOM);
		if(priceRoom != null ){
			String priceRoomCost = priceRoom[0].replace(",", "");
			try {
				room.setPriceRoom(Long.parseLong(priceRoomCost));
				multiParameters.remove(AppConstant.PRICE_ROOM);
			} catch (NumberFormatException e) {
				e.printStackTrace();
				return null;
			}
		}
		
		String[] sqft = multiParameters.get(AppConstant.SQFT);
		if(sqft != null ){
			try{
				room.setSqft(Long.parseLong(sqft[0]));
				multiParameters.remove(AppConstant.SQFT);
			}catch(NumberFormatException ex){
				return null;
			}
		}
		
		String[] houseValue = multiParameters.get(AppConstant.HOUSE);
		if(houseValue != null ){
			House house = houseSerive.getHouseByCode(houseValue[0]);
			room.setHouse(house);
			multiParameters.remove(AppConstant.HOUSE);
		}
		
		// set status to true
		room.setStatus(Boolean.valueOf("true"));
		room.setIsDisplay(Boolean.valueOf("false"));
		return room;
	}
	
	/* edit room */
 	@RequestMapping(value = "/edit/{idRoom}", method = RequestMethod.GET)
 	public ModelAndView editRoom(@PathVariable Long idRoom){
 		Room room = roomService.findRoomByIdAndGetHouse(idRoom);
 		List<House> houses = houseSerive.getAll();
		List<Utility> utilities = utilityService.getAllUtilities();
		House house = room.getHouse();
		
		List<Object[]> roomUtility = roomUtilityService.getAllUtilityByRoomId(idRoom);
		List<Utility> resultCombine = combineUtility(utilities, roomUtility);
		
		ModelAndView model = new ModelAndView("/admin/rooms/edit");
		
		model.addObject("houses", houses);
		model.addObject("room", room);
		model.addObject("house", house);
		model.addObject("resultCombine", resultCombine);
		
		return model;
 	}
 	
 	@RequestMapping(value = "/edit", method = RequestMethod.POST)
 	public @ResponseBody String saveEditProduct(HttpServletRequest request){
 		Map<String, String[]> multiParameters = request.getParameterMap();
 		// merge room and utility;
 		if(multiParameters.get("idRoom")[0] != null){
 			Room roomTarget = roomService.findRoomById(Long.parseLong(multiParameters.get("idRoom")[0]));
 			Room roomMerge = setValueForRoom(roomTarget, multiParameters);
 			if(roomMerge != null){ // input invalid in setValueForHouse
 				roomMerge = roomService.merge(roomMerge);
	 			roomUtilityService.deleteAllUtilitiesRoomUtility(Long.parseLong(multiParameters.get("idRoom")[0]));
	 			List<Utility> utilities = setUtilities(multiParameters);
				for(Utility utility :utilities){
					RoomUtility roomUtility = new RoomUtility();
					roomUtility.setRoom(roomMerge);
					roomUtility.setUtility(utility);
					roomUtility.setStatus(Boolean.valueOf("true"));
					roomUtilityService.merge(roomUtility);
				}
 				return roomMerge.getIdRoom() + ";" + roomMerge.getNameRoom();
 			}
 		}
 		return "fail";
 	}
	
 	/**
 	 * get All data to return list rooms
 	 * @return
 	 */
 	@RequestMapping(value = "/getDataRooms", method = RequestMethod.GET)
    public @ResponseBody List<Room> getDataRooms() {
    	List<Room> listRooms = roomService.getAll();
    	for(Room room : listRooms){
    		room.setHouse(null);
    		room.setRoomRentals(null);
    		room.setRoomUtilities(null);
    		room.setImages(null);
    	}
	    return listRooms;
    }
 	
 	/**
 	 * upload image for room
 	 * @param houseId
 	 * @return
 	 */
 	/* get method upload house's image */
	@RequestMapping(value = "/uploadImages", method = RequestMethod.GET, produces="text/html; charset=utf-8")
	public ModelAndView uploadImages(@RequestParam(value="roomId") String roomId) {
		ModelAndView model = new ModelAndView("admin/rooms/uploadImages");
		Room room = roomService.findRoomById(Long.parseLong(roomId));
		model.addObject("roomId", room.getIdRoom());
		model.addObject("roomName", room.getNameRoom());
		
		List<Image> images = imageService.getAllImagesByRoomId(Long.parseLong(roomId));
		
		if(images != null && images.size() > 0){
			for(Image image: images){
				image.setUrl("/" + AppConstant.APP_URL + "/admin/picture/"+ image.getId());
	            image.setThumbnailUrl("/" + AppConstant.APP_URL + "/admin/thumbnail/"+ image.getId());
	            image.setDeleteUrl("/" + AppConstant.APP_URL + "/admin/delete/"+ image.getId());
	            image.setDeleteType("DELETE");
	            image.setHouse(null);
			}
		}
		model.addObject("images", images);
		return model;
	}
	
	@RequestMapping(value = "/uploadImages", method = RequestMethod.POST)
    public @ResponseBody Map<String, Object> upload(MultipartHttpServletRequest request, HttpServletResponse response) {
        Iterator<String> itr = request.getFileNames();
        MultipartFile mpf;
        List<Image> list = new LinkedList<Image>();
        String roomIdValue = request.getParameter("roomIdValue");
        Room room = roomService.findRoomById(Long.parseLong(roomIdValue));
        while (itr.hasNext()) {
            mpf = request.getFile(itr.next());
            
            String newFilenameBase = UUID.randomUUID().toString();
            String originalFileExtension = mpf.getOriginalFilename().substring(mpf.getOriginalFilename().lastIndexOf("."));
            String newFilename = newFilenameBase + originalFileExtension;
            
            String filename = "/WEB-INF" ;
			String pathname = context.getRealPath(filename);
			
			File dir = new File(pathname + File.separator + "images");
			
			if(!dir.exists()){
				dir.mkdirs();
			}
			
            String contentType = mpf.getContentType();
            
            File newFile = new File(dir.getAbsolutePath() + File.separator + newFilename);
            try {
                mpf.transferTo(newFile);
                
                BufferedImage thumbnail = Scalr.resize(ImageIO.read(newFile), 80);
                String thumbnailFilename = newFilenameBase + "-thumbnail.png";
                File thumbnailFile = new File(dir.getAbsolutePath() + File.separator + thumbnailFilename);
                ImageIO.write(thumbnail, "png", thumbnailFile);
                
                Image image = new Image();
                image.setName(mpf.getOriginalFilename());
                image.setThumbnailFilename(thumbnailFilename);
                image.setNewFilename(newFilename);
                image.setContentType(contentType);
                image.setSize(mpf.getSize());
                image.setThumbnailSize(thumbnailFile.length());
                image.setDateCreated(new Date());
                image.setLastUpdated(new Date());
                image.setRoom(room);
                image = imageService.merge(image);
                
                image.setUrl("/" + AppConstant.APP_URL + "/admin/picture/"+ image.getId());
                image.setThumbnailUrl("/" + AppConstant.APP_URL + "/admin/thumbnail/"+ image.getId());
                image.setDeleteUrl("/" + AppConstant.APP_URL + "/admin/delete/"+ image.getId());
                image.setDeleteType("DELETE");
                image.setRoom(null);
                list.add(image);
                
            } catch(IOException e) {
                log.error("Could not upload file " + mpf.getOriginalFilename(), e);
            }
            
        }
        
        Map<String, Object> files = new HashMap<String, Object>();
        files.put("files", list);
        return files;
    }
	
 	/**
 	 * return list utility checked in create/ edit room
 	 * @param multiParameters
 	 * @return
 	 */
	private List<Utility> setUtilities(Map<String, String[]> multiParameters){
		List<Utility> utilities = new ArrayList<Utility>();
		for(String value : multiParameters.keySet()) {
			if(value != null && multiParameters.get(value)[0].equals("true")){
				Utility utility = utilityService.getUtilityByCode(value);
				utilities.add(utility);
			}
		}
		return utilities;
	}
	
	/* merge utility house with house_utility*/
	private List<Utility> combineUtility(
			List<Utility> listUtility, List<Object[]> houseUtilities) {
		List<Utility> resultCombine = new ArrayList<Utility>();
		if(listUtility != null && listUtility.size() > 0){
			// create list dto => attribute + value
			for (Utility utility : listUtility) {
				if(houseUtilities.size() > 0){
					for(int i = 0; i< houseUtilities.size(); i++){
						if(utility.getCodeUtility().equals(houseUtilities.get(i)[2])){
							Utility dto = new Utility();
							dto.setCodeUtility(utility.getCodeUtility());
							dto.setNameUtility(utility.getNameUtility());
							dto.setStatus(Boolean.valueOf("true"));
							resultCombine.add(dto);
							break;
						}
						if(i == houseUtilities.size() - 1){
							Utility dto = new Utility();
							dto.setCodeUtility(utility.getCodeUtility());
							dto.setNameUtility(utility.getNameUtility());
							dto.setStatus(Boolean.valueOf("false"));
							resultCombine.add(dto);
						}
					}
				}else{
					Utility dto = new Utility();
					dto.setCodeUtility(utility.getCodeUtility());
					dto.setNameUtility(utility.getNameUtility());
					dto.setStatus(Boolean.valueOf("false"));
					resultCombine.add(dto);
				}
			}
		}
		return resultCombine;
	}
	
	/**
	 * Mark rooms to make Cavas
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/setDisplayCavas", method = RequestMethod.POST)
    public @ResponseBody String setDisplayCavas(HttpServletRequest request) {
    	List<Long> listLongId = new ArrayList<Long>();
    	Map<String, String[]> multiParameters = request.getParameterMap();
    	String[] listIdRooms = multiParameters.get("listIdRooms");
    	if(listIdRooms != null){
    		String[] listIdRoomsValue = listIdRooms[0].split(",");
    		try{
    			for(int i = 0; i < listIdRoomsValue.length; i++){
    				Long idNews = Long.parseLong(listIdRoomsValue[i]);
    				listLongId.add(idNews);
    			}
    			Parameter parameter = parameterService.getParameterByCode(AppConstant.ROOMS_CODE);
    			if(listLongId.size() > 0 && parameter.getValue() >= listLongId.size()){
    				roomService.setDisplayCavas(listLongId);
    			}else if(listLongId.size() > 0){
    				return "fail";
    			}
    		}catch(NumberFormatException exception){
    			return "fail";
    		}
    	}
    	return "success";
    }
	
	// mark image to display on the cavas
 	@RequestMapping(value = "/markImage/{roomId}", method = RequestMethod.GET)
 	public ModelAndView markImage(@PathVariable Long roomId){
		Room room = roomService.findRoomById(roomId);
		ModelAndView model = new ModelAndView("/admin/rooms/markImages");
		model.addObject("room", room);
		return model;
 	}
 	
 	// getData mark image to display on the cavas
  	@RequestMapping(value = "/markImage/getData", method = RequestMethod.GET)
  	public @ResponseBody List<Image> markImageGetData(HttpServletRequest request){
  		String[] roomIdValue = request.getParameterMap().get("roomId");
  		Long roomId = Long.parseLong(roomIdValue[0]);
  		List<Image> images = imageService.getListImageByAId(roomId, AppConstant.ROOMS_CODE);
		
		if(images != null && images.size() > 0){
			for(Image image: images){
				image.setUrl("/" + AppConstant.APP_URL + "/admin/picture/"+ image.getId());
	            image.setThumbnailUrl("/" + AppConstant.APP_URL + "/admin/thumbnail/"+ image.getId());
	            image.setRoom(null);
			}
		}
 		return images;
  	}
 	
 	@RequestMapping(value = "/markImageFormSubmit", method = RequestMethod.POST)
 	public @ResponseBody String markImageFormSubmit(HttpServletRequest request){
 		Map<String, String[]> multiParameters = request.getParameterMap();
 		// merge room and attribute;
 		if(multiParameters.get("imageId")[0] != null){
 			imageService.markImageFormSubmit(Long.parseLong(multiParameters.get("imageId")[0]), AppConstant.ROOMS_CODE);
 			return "success";
 		}
 		return "fail";
 	}
}
